/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.inspur.edp.cef.generator.repository.adaptor;


import com.inspur.edp.caf.generator.baseInfo.TypeInfo;
import com.inspur.edp.caf.generator.field.FieldGenerator;
import com.inspur.edp.caf.generator.item.ClassGeneratorContext;
import com.inspur.edp.caf.generator.method.ClassMethodGenerator;
import com.inspur.edp.cef.api.repository.INestedDataReader;
import com.inspur.edp.cef.designtime.api.IGspCommonField;
import com.inspur.edp.cef.designtime.api.element.GspAssociation;
import com.inspur.edp.cef.designtime.api.element.GspElementDataType;
import com.inspur.edp.cef.designtime.api.element.GspElementObjectType;
import com.inspur.edp.cef.entity.dependenceTemp.DataValidator;
import com.inspur.edp.cef.generator.overall.GeneratorUtil;
import com.inspur.edp.cef.generator.repository.AssemblerInfo;
import com.inspur.edp.cef.generator.repository.CefRepoAssembler;
import com.inspur.edp.cef.generator.repository.RepositoryGenUtil;
import com.inspur.edp.cef.generator.repository.adaptor.method.InitAssosGenerator;
import com.inspur.edp.cef.generator.repository.adaptor.method.NestedInitColumnGenerator;
import com.inspur.edp.cef.generator.repository.adaptor.method.NestedInitReaderGenerator;
import com.inspur.edp.cef.generator.repository.adaptor.method.createinstance.NestedCreateInsGenerator;
import com.inspur.edp.cef.generator.repository.adaptor.method.createpropertydefmethod.BinaryPropertyCreateDefMethodGenerator;
import com.inspur.edp.cef.generator.repository.adaptor.method.createpropertydefmethod.BoolPropertyCreateDefMethodGenerator;
import com.inspur.edp.cef.generator.repository.adaptor.method.createpropertydefmethod.CreateUdtDefMethodGenerator;
import com.inspur.edp.cef.generator.repository.adaptor.method.createpropertydefmethod.DecimalPropertyCreateDefMethodGenerator;
import com.inspur.edp.cef.generator.repository.adaptor.method.createpropertydefmethod.EntityGetAssocationDBMappingMethodGenerator;
import com.inspur.edp.cef.generator.repository.adaptor.method.createpropertydefmethod.GetDateTimePropetyCreateDefMethodGenerator;
import com.inspur.edp.cef.generator.repository.adaptor.method.createpropertydefmethod.IntPropertyCreateDefMethodGenerator;
import com.inspur.edp.cef.generator.repository.adaptor.method.readproperty.DataTypeReadPropertyGenerator;
import com.inspur.edp.cef.generator.repository.adaptor.property.DataTypeMappingGenerator;
import com.inspur.edp.cef.generator.repository.common.IntermediateType;
import com.inspur.edp.cef.generator.repository.dac.DataTypeDacGenContext;
import com.inspur.edp.cef.generator.repository.dac.NestedDacGenContext;
import com.inspur.edp.cef.repository.adaptor.NestedAdaptor;
import com.inspur.edp.cef.repository.assembler.AssociationInfo;
import com.inspur.edp.cef.repository.assembler.DataTypeAssembler;
import com.inspur.edp.cef.repository.assembler.nesteddatatype.NestedColumnInfo;
import com.inspur.edp.cef.repository.assembler.nesteddatatype.NestedDataTypeAssembler;
import com.inspur.edp.cef.repository.dbcolumninfo.DbColumnInfo;
import com.inspur.edp.cef.repository.dbcolumninfo.DbColumnInfoCollection;
import com.inspur.edp.udt.designtime.api.entity.ComplexDataTypeDef;
import com.inspur.edp.udt.designtime.api.entity.UnifiedDataTypeDef;
import com.inspur.edp.udt.designtime.api.entity.dbInfo.ColumnMapType;
import org.eclipse.jdt.core.dom.Modifier;

import java.util.ArrayList;

public abstract class NestedAdaptorGenerator extends DataTypeAdaptorGenerator {
    private DataTypeDacGenContext dacContext;
    private java.util.ArrayList<AssemblerInfo> extendAssemblers;
    private java.util.HashMap<String, String> mappingPropNames = new java.util.HashMap<String, String>();
    private java.util.ArrayList<INestedDataReader> dataReaders = new java.util.ArrayList<INestedDataReader>();
    private CefRepoAssembler baseAssembler;

    public NestedAdaptorGenerator(DataTypeDacGenContext dacContext, String nodeCode) {
        //wangmj 待更新
        super(dacContext.getReposContext().getCefContext().getCefGenContext().getCommonDataType(), dacContext, nodeCode);
        this.dacContext = dacContext;
        dacContext.setGspCommonDataType(dacContext.getReposContext().getCefContext().getCefGenContext().getCommonDataType());
        this.extendAssemblers = extendAssemblers;
//        initDataReader();
//        init();
    }

    //todo wangmj
    protected NestedDataTypeAssembler getAssembler() {
        return null;
    }

    private void initDataReader() {
        dataReaders.addAll(getAssembler().getDataReaders());
        if (extendAssemblers == null || extendAssemblers.size() < 1) {
            return;
        }
        for (AssemblerInfo extendAssembler : extendAssemblers) {
            ArrayList<INestedDataReader> extendReaders = ((NestedDataTypeAssembler) extendAssembler.getAssemblerInstance()).getDataReaders();
            if (extendReaders != null) {
                dataReaders.addAll(extendReaders);
            }
        }
    }

    @Override
    protected ClassGeneratorContext createClassInfoContext() {
        return new ClassGeneratorContext();
    }

    @Override
    protected void doInitialize() {
        super.doInitialize();
        ((NestedDacGenContext) ((dacContext))).setGeneratedAdaptorType(new IntermediateType(getName(), getNameSpace()));
    }

    protected String getNameSpace() {
        return DacContext.getReposContext().getCefContext().getNameSpace();
    }

    @Override
    protected String getName() {
        return GeneratorUtil.getName(RepositoryGenUtil.getConfigID(DacContext.getReposContext().getCefContext())) + "adaptor";

    }

    @Override
    protected TypeInfo setParentClass() {
        return new TypeInfo(NestedAdaptor.class);
    }

    @Override
    protected java.util.ArrayList<FieldGenerator> createFieldGenerator() {

        ArrayList<FieldGenerator> list = super.createFieldGenerator();
        if (list == null) {
            list = new java.util.ArrayList<FieldGenerator>();
        }
        buildMappingGenerator(list);
        return list;
    }

    private void buildMappingGenerator(java.util.ArrayList<FieldGenerator> filedGenerators) {

        for (IGspCommonField gspCommonField : DacContext.getGspCommonDataType().getContainElements()) {
            if (!gspCommonField.getIsUdt())
                continue;
            DataTypeMappingGenerator mppingGen = new DataTypeMappingGenerator(dacContext, gspCommonField, gspCommonField.getLabelID());
            filedGenerators.add(mppingGen);
            mappingPropNames.put(gspCommonField.getLabelID(), mppingGen.getGeneratedName());
        }
    }

    @Override
    protected ArrayList<Modifier.ModifierKeyword> getAccessModifier() {
        ArrayList<Modifier.ModifierKeyword> list = new ArrayList<Modifier.ModifierKeyword>();
        list.add(Modifier.ModifierKeyword.PUBLIC_KEYWORD);
        return list;
    }

    @Override
    protected java.util.ArrayList<ClassMethodGenerator> createMethodGenerators() {
        ArrayList<ClassMethodGenerator> list = super.createMethodGenerators();
        if (list == null) {
            list = new java.util.ArrayList<ClassMethodGenerator>();
        }
        list.add(new NestedInitColumnGenerator(dacContext.getReposContext().getCefContext(),
            gspCommonDataType));
        list.add(new NestedInitReaderGenerator(new ArrayList<>()));
        list.add(getCreateInstanceGenerator(dacContext, getAssembler(), mappingPropNames));
        InitAssosGenerator initAssoGen = new InitAssosGenerator(
            DacContext.getReposContext().getCefContext().getCefGenContext(), gspCommonDataType,
            null);
        list.add(initAssoGen);
        return list;
    }

    @Override
    public DataTypeReadPropertyGenerator getReadPropertyGenerator() {
        return new DataTypeReadPropertyGenerator(dacContext, gspCommonDataType, NodeCode, false, DbColumns);
    }

    private NestedCreateInsGenerator getCreateInstanceGenerator(DataTypeDacGenContext dacGenContext, NestedDataTypeAssembler assembler, java.util.HashMap<String, String> propNames) {
        return new NestedCreateInsGenerator(dacGenContext);
    }

//    private void init() {
//        initColumns();
//        initAssociationInfo();
//    }

    ///#region InitColumn
    private void initColumns() {
        DbColumns = new DbColumnInfoCollection();
        for (NestedColumnInfo columnInfo : getAssembler().getColumnInfos().values()) {
            DbColumnInfo dbColumnInfo = transDbColumnInfo(columnInfo);
            DbColumns.add(dbColumnInfo);
        }
        //ContainColumns.AddRange(AssemblerItem.ContainColumns);
//		if (ExtendAssemblers == null || ExtendAssemblers.size() < 1)
//		{
//			return;
//		}

//		for (AssemblerInfo extendAssmeblerItem : ExtendAssemblers)
//		{
//			//ContainColumns.AddRange(extendAssmeblerItem.AssemblerInstance);
//			initExtendColumns(extendAssmeblerItem.getAssemblerInstance());
//		}
    }

    private void initExtendColumns(DataTypeAssembler assemblerInstance) {
        //TODO: udt暂不支持extend
        //var extendAssembly = assemblerInstance as ExtendEntityAssembler;
        //foreach (var columnInfo in extendAssembly.ContainColumns)
        //{
        //    var dbColumnInfo = TransDbColumnInfo(columnInfo);
        //    DbColumns.Add(dbColumnInfo);
        //}
    }

    private DbColumnInfo transDbColumnInfo(NestedColumnInfo columnInfo) {
        DataValidator.checkForNullReference(columnInfo, "columnInfo");
        DbColumnInfo tempVar = new DbColumnInfo();
        tempVar.setColumnName(columnInfo.getColumnName());
        tempVar.setDbColumnName(columnInfo.getColumnName());
        tempVar.setColumnType(columnInfo.getColumnType());
        tempVar.setIsAssociateRefElement(columnInfo.getIsAssociateRefElement());
        tempVar.setIsMultiLang(columnInfo.getIsMultiLang());
        tempVar.setIsUdtElement(columnInfo.getIsUdtElement());
        tempVar.setIsAssociation(columnInfo.getIsAssociation());
        tempVar.setIsEnum(columnInfo.getIsEnum());
        tempVar.setBelongElementLabel(columnInfo.getBelongElementLabel());
        DbColumnInfo column = tempVar;
        //Length = dboColumn.Length,
        //Precision = dboColumn.Precision,
        //DefaultValue = dboColumn.DefaultValue,
        //TypeTransProcesser = columnInfo.TypeTransProcesser
        return column;
    }


    protected void addGetPropertyValueGenerator(java.util.ArrayList<ClassMethodGenerator> gens, IGspCommonField gspCommonField) {


        String propertyName = gspCommonField.getLabelID();

        if (gspCommonDataType instanceof UnifiedDataTypeDef) {
            if (gspCommonDataType instanceof ComplexDataTypeDef) {//多值udt不包含
                if(((ComplexDataTypeDef)gspCommonDataType).getDbInfo().getMappingType() == ColumnMapType.SingleColumn){
                    return;
                }
            }
        }
		if(gspCommonField.getIsUdt()){
			UnifiedDataTypeDef udt = (UnifiedDataTypeDef)DacContext.getReposContext().getCefContext().getCefGenContext().getMetadataJitContext().getMetadata(gspCommonField.getUdtID()).getContent();
			gens.add(new CreateUdtDefMethodGenerator(gspCommonField, udt, DacContext, NodeCode));
			//应该是判断所引用的udt对象的值？？
			if (gspCommonDataType instanceof ComplexDataTypeDef) {//多值udt不包含
				return;
			}
			if(gspCommonField.getObjectType() == GspElementObjectType.Association){
				addAssgetDBMappingGenerator(gens, gspCommonField);
			}
			return;
		}
		if (gspCommonField.getIsVirtual() || gspCommonField.getObjectType() == GspElementObjectType.DynamicProp) {
			return;
		}
		if (gspCommonField.getObjectType() == GspElementObjectType.Association) {
			addAssgetPropValueGenerator(gens, gspCommonField);
			addAssgetDBMappingGenerator(gens, gspCommonField);
			return;
		} else if (gspCommonField.getObjectType() == GspElementObjectType.Enum) {
			addEnumgetPropValueGenerator(gens, gspCommonField);
			return;
		} else {
			addNormalgetPropValueGenerator(gens, gspCommonField);
		}
    }

    	private void addAssgetDBMappingGenerator(java.util.ArrayList<ClassMethodGenerator> gens, IGspCommonField gspCommonField) {
		GspAssociation associationInfo = getAssociationInfo(gspCommonField);
		gens.add(new EntityGetAssocationDBMappingMethodGenerator(DacContext.getReposContext().getCefContext().getCefGenContext(), gspCommonDataType, associationInfo,  gspCommonField.getLabelID()));
	}

    protected void addNormalgetPropValueGenerator(java.util.ArrayList<ClassMethodGenerator> gens, IGspCommonField gspCommonField) {
        if (gspCommonField.getMDataType() == GspElementDataType.String
            || gspCommonField.getMDataType() == GspElementDataType.Text) {
            gens.add(getStringPropCreateDefMethodGenerator(gspCommonField));
        } else if (gspCommonField.getMDataType() == GspElementDataType.Boolean) {
            gens.add(new BoolPropertyCreateDefMethodGenerator(gspCommonField.getLabelID(),
                gspCommonField));
        } else if (gspCommonField.getMDataType() == GspElementDataType.Integer) {
            gens.add(new IntPropertyCreateDefMethodGenerator(gspCommonField.getLabelID(),
                gspCommonField));
        } else if (gspCommonField.getMDataType() == GspElementDataType.Date
            || gspCommonField.getMDataType() == GspElementDataType.DateTime) {
            gens.add(new GetDateTimePropetyCreateDefMethodGenerator(gspCommonField.getLabelID(),
                gspCommonField));
        } else if (gspCommonField.getMDataType() == GspElementDataType.Decimal) {
            gens.add(new DecimalPropertyCreateDefMethodGenerator(gspCommonField.getLabelID(),
                gspCommonField));
        } else if (gspCommonField.getMDataType() == GspElementDataType.Binary) {
            gens.add(new BinaryPropertyCreateDefMethodGenerator(gspCommonField.getLabelID(),
                gspCommonField));
        } else {
//			throw new RuntimeException("AddNormalGetPropValueGenerator");
//		}
        }
    }
    ///#endregion

    ///#region InitAssociation
//    private void initAssociationInfo() {
//        //todo wangmj
//        java.util.ArrayList<AssociationInfo> associtateList = getAssembler().getAssociationInfos();
//        if (associtateList != null && associtateList.size() > 0) {
//            associationInfos.addAll(associtateList);
//        }
////		if (ExtendAssemblers == null || ExtendAssemblers.size() < 1)
////		{
////			return;
////		}
////
////		for (AssemblerInfo extendAssmeblerItem : ExtendAssemblers)
////		{
////			ArrayList<AssociationInfo> extendAssocitateList = ((ExtendEntityAssembler)((extendAssmeblerItem.getAssemblerInstance() instanceof ExtendEntityAssembler) ? extendAssmeblerItem.getAssemblerInstance() : null)).getAssociationInfos();
////			if (extendAssocitateList != null && extendAssocitateList.size() > 0)
////			{
////				associationInfos.addAll(extendAssocitateList);
////			}
////		}
//    }
}
